<script>
export default {
  components: {},
  data () {
    return {
      radio: 0,
      activeName: '1',
    };
  },
  computed: {
    isButtonDisabled() {
      return this.radio === 0;
    }
  },
  methods: {
    check(radio) {
      console.log(radio)
      if (radio === 3) {
        this.$message.success('恭喜你，答对啦！')
      } else {
        this.$message.error('很遗憾，答错啦！')
      }
    },
  }
}
</script>

<template>
  <div>
    <div>
      <h1 align="center">2.3 GCC 堆栈保护技术</h1>
      <el-divider></el-divider>
      <h3>技术简介</h3>
      Linux 中有各种各样的安全防护，其中 ASLR 是由内核直接提供的，通过系统配置文件控制。NX，Canary，PIE，RELRO 等需要在编译时根据各项参数开启或关闭。未指定参数时，使用默认设置。
      <br><b>CANARY</b><br>
      启用 CANARY 后，函数开始执行的时候会先往栈里插入 canary 信息，当函数返回时验证插入的 canary 是否被修改，如果是，则说明发生了栈溢出，程序停止运行。
      <br>下面是一个例子：<br>
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-c"><span class="com">#include</span><span class="pln"> </span><span class="str">&lt;stdio.h&gt;</span></code></li><li class="L1"><code class="lang-c"><span class="kwd">void</span><span class="pln"> main</span><span class="pun">(</span><span class="typ">int</span><span class="pln"> argc</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">char</span><span class="pln"> </span><span class="pun">**</span><span class="pln">argv</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></code></li><li class="L2"><code class="lang-c"><span class="pln">    </span><span class="kwd">char</span><span class="pln"> buf</span><span class="pun">[</span><span class="lit">10</span><span class="pun">];</span></code></li><li class="L3"><code class="lang-c"><span class="pln">    scanf</span><span class="pun">(</span><span class="str">"%s"</span><span class="pun">,</span><span class="pln"> buf</span><span class="pun">);</span></code></li><li class="L4"><code class="lang-c"><span class="pun">}</span></code></li></ol></pre>
      我们先开启 CANARY，来看看执行的结果：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">$ gcc </span><span class="pun">-</span><span class="pln">m32 </span><span class="pun">-</span><span class="pln">fstack</span><span class="pun">-</span><span class="pln">protector canary</span><span class="pun">.</span><span class="pln">c </span><span class="pun">-</span><span class="pln">o f</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L1"><code class="lang-text"><span class="pln">$ python </span><span class="pun">-</span><span class="pln">c </span><span class="str">'print("A"*20)'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">./</span><span class="pln">f</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L2"><code class="lang-text"><span class="pun">***</span><span class="pln"> stack smashing detected </span><span class="pun">***:</span><span class="pln"> </span><span class="pun">./</span><span class="pln">f</span><span class="pun">.</span><span class="kwd">out</span><span class="pln"> terminated</span></code></li><li class="L3"><code class="lang-text"><span class="typ">Segmentation</span><span class="pln"> fault </span><span class="pun">(</span><span class="pln">core dumped</span><span class="pun">)</span></code></li></ol></pre>
      接下来关闭 CANARY：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">$ gcc </span><span class="pun">-</span><span class="pln">m32 </span><span class="pun">-</span><span class="pln">fno</span><span class="pun">-</span><span class="pln">stack</span><span class="pun">-</span><span class="pln">protector canary</span><span class="pun">.</span><span class="pln">c </span><span class="pun">-</span><span class="pln">o fno</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L1"><code class="lang-text"><span class="pln">$ python </span><span class="pun">-</span><span class="pln">c </span><span class="str">'print("A"*20)'</span><span class="pln"> </span><span class="pun">|</span><span class="pln"> </span><span class="pun">./</span><span class="pln">fno</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L2"><code class="lang-text"><span class="typ">Segmentation</span><span class="pln"> fault </span><span class="pun">(</span><span class="pln">core dumped</span><span class="pun">)</span></code></li></ol></pre>
      可以看到当开启 CANARY 的时候，提示检测到栈溢出和段错误，而关闭的时候，只有提示段错误。
      <br>下面对比一下反汇编代码上的差异：
      <br>开启 CANARY 时：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">gdb</span><span class="pun">-</span><span class="pln">peda$ disassemble main</span></code></li><li class="L1"><code class="lang-text"><span class="typ">Dump</span><span class="pln"> of assembler code </span><span class="kwd">for</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> main</span><span class="pun">:</span></code></li><li class="L2"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005ad</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">0</span><span class="pun">&gt;:</span><span class="pln">    lea    ecx</span><span class="pun">,[</span><span class="pln">esp</span><span class="pun">+</span><span class="lit">0x4</span><span class="pun">]</span></code></li><li class="L3"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005b1</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">4</span><span class="pun">&gt;:</span><span class="pln">    </span><span class="kwd">and</span><span class="pln">    esp</span><span class="pun">,</span><span class="lit">0xfffffff0</span></code></li><li class="L4"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005b4</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">7</span><span class="pun">&gt;:</span><span class="pln">    push   DWORD PTR </span><span class="pun">[</span><span class="pln">ecx</span><span class="pun">-</span><span class="lit">0x4</span><span class="pun">]</span></code></li><li class="L5"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005b7</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">10</span><span class="pun">&gt;:</span><span class="pln">    push   ebp</span></code></li><li class="L6"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005b8</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">11</span><span class="pun">&gt;:</span><span class="pln">    mov    ebp</span><span class="pun">,</span><span class="pln">esp</span></code></li><li class="L7"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005ba</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">13</span><span class="pun">&gt;:</span><span class="pln">    push   ebx</span></code></li><li class="L8"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005bb</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">14</span><span class="pun">&gt;:</span><span class="pln">    push   ecx</span></code></li><li class="L9"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005bc</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">15</span><span class="pun">&gt;:</span><span class="pln">    </span><span class="kwd">sub</span><span class="pln">    esp</span><span class="pun">,</span><span class="lit">0x20</span></code></li><li class="L0"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005bf</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">18</span><span class="pun">&gt;:</span><span class="pln">    call   </span><span class="lit">0x611</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">__x86</span><span class="pun">.</span><span class="pln">get_pc_thunk</span><span class="pun">.</span><span class="pln">ax</span><span class="pun">&gt;</span></code></li><li class="L1"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005c4</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">23</span><span class="pun">&gt;:</span><span class="pln">    add    eax</span><span class="pun">,</span><span class="lit">0x1a3c</span></code></li><li class="L2"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005c9</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">28</span><span class="pun">&gt;:</span><span class="pln">    mov    edx</span><span class="pun">,</span><span class="pln">ecx</span></code></li><li class="L3"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005cb</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">30</span><span class="pun">&gt;:</span><span class="pln">    mov    edx</span><span class="pun">,</span><span class="pln">DWORD PTR </span><span class="pun">[</span><span class="pln">edx</span><span class="pun">+</span><span class="lit">0x4</span><span class="pun">]</span></code></li><li class="L4"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005ce</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">33</span><span class="pun">&gt;:</span><span class="pln">    mov    DWORD PTR </span><span class="pun">[</span><span class="pln">ebp</span><span class="pun">-</span><span class="lit">0x1c</span><span class="pun">],</span><span class="pln">edx</span></code></li><li class="L5"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005d1</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">36</span><span class="pun">&gt;:</span><span class="pln">    mov    ecx</span><span class="pun">,</span><span class="pln">DWORD PTR gs</span><span class="pun">:</span><span class="lit">0x14</span><span class="pln">                </span><span class="pun">;</span><span class="pln"> </span><span class="pun">将</span><span class="pln"> canary </span><span class="pun">值存入</span><span class="pln"> ecx</span></code></li><li class="L6"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005d8</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">43</span><span class="pun">&gt;:</span><span class="pln">    mov    DWORD PTR </span><span class="pun">[</span><span class="pln">ebp</span><span class="pun">-</span><span class="lit">0xc</span><span class="pun">],</span><span class="pln">ecx            </span><span class="pun">;</span><span class="pln"> </span><span class="pun">在栈</span><span class="pln"> ebp</span><span class="pun">-</span><span class="lit">0xc</span><span class="pln"> </span><span class="pun">处插入</span><span class="pln"> canary</span></code></li><li class="L7"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005db</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">46</span><span class="pun">&gt;:</span><span class="pln">    xor    ecx</span><span class="pun">,</span><span class="pln">ecx</span></code></li><li class="L8"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005dd</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">48</span><span class="pun">&gt;:</span><span class="pln">    </span><span class="kwd">sub</span><span class="pln">    esp</span><span class="pun">,</span><span class="lit">0x8</span></code></li><li class="L9"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005e0</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">51</span><span class="pun">&gt;:</span><span class="pln">    lea    edx</span><span class="pun">,[</span><span class="pln">ebp</span><span class="pun">-</span><span class="lit">0x16</span><span class="pun">]</span></code></li><li class="L0"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005e3</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">54</span><span class="pun">&gt;:</span><span class="pln">    push   edx</span></code></li><li class="L1"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005e4</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">55</span><span class="pun">&gt;:</span><span class="pln">    lea    edx</span><span class="pun">,[</span><span class="pln">eax</span><span class="pun">-</span><span class="lit">0x1940</span><span class="pun">]</span></code></li><li class="L2"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005ea</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">61</span><span class="pun">&gt;:</span><span class="pln">    push   edx</span></code></li><li class="L3"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005eb</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">62</span><span class="pun">&gt;:</span><span class="pln">    mov    ebx</span><span class="pun">,</span><span class="pln">eax</span></code></li><li class="L4"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005ed</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">64</span><span class="pun">&gt;:</span><span class="pln">    call   </span><span class="lit">0x450</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">__isoc99_scanf@plt</span><span class="pun">&gt;</span></code></li><li class="L5"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005f2</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">69</span><span class="pun">&gt;:</span><span class="pln">    add    esp</span><span class="pun">,</span><span class="lit">0x10</span></code></li><li class="L6"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005f5</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">72</span><span class="pun">&gt;:</span><span class="pln">    nop</span></code></li><li class="L7"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005f6</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">73</span><span class="pun">&gt;:</span><span class="pln">    mov    eax</span><span class="pun">,</span><span class="pln">DWORD PTR </span><span class="pun">[</span><span class="pln">ebp</span><span class="pun">-</span><span class="lit">0xc</span><span class="pun">]</span><span class="pln">                </span><span class="pun">;</span><span class="pln"> </span><span class="pun">从栈中取出</span><span class="pln"> canary</span></code></li><li class="L8"><code class="lang-text"><span class="pln">   </span><span class="lit">0x000005f9</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">76</span><span class="pun">&gt;:</span><span class="pln">    xor    eax</span><span class="pun">,</span><span class="pln">DWORD PTR gs</span><span class="pun">:</span><span class="lit">0x14</span><span class="pln">                    </span><span class="pun">;</span><span class="pln"> </span><span class="pun">检测</span><span class="pln"> canary </span><span class="pun">值</span></code></li><li class="L9"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000600</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">83</span><span class="pun">&gt;:</span><span class="pln">    je     </span><span class="lit">0x607</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">main</span><span class="pun">+</span><span class="lit">90</span><span class="pun">&gt;</span></code></li><li class="L0"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000602</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">85</span><span class="pun">&gt;:</span><span class="pln">    call   </span><span class="lit">0x690</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">__stack_chk_fail_local</span><span class="pun">&gt;</span></code></li><li class="L1"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000607</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">90</span><span class="pun">&gt;:</span><span class="pln">    lea    esp</span><span class="pun">,[</span><span class="pln">ebp</span><span class="pun">-</span><span class="lit">0x8</span><span class="pun">]</span></code></li><li class="L2"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000060a</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">93</span><span class="pun">&gt;:</span><span class="pln">    pop    ecx</span></code></li><li class="L3"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000060b</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">94</span><span class="pun">&gt;:</span><span class="pln">    pop    ebx</span></code></li><li class="L4"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000060c</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">95</span><span class="pun">&gt;:</span><span class="pln">    pop    ebp</span></code></li><li class="L5"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000060d</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">96</span><span class="pun">&gt;:</span><span class="pln">    lea    esp</span><span class="pun">,[</span><span class="pln">ecx</span><span class="pun">-</span><span class="lit">0x4</span><span class="pun">]</span></code></li><li class="L6"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000610</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">99</span><span class="pun">&gt;:</span><span class="pln">    ret</span></code></li><li class="L7"><code class="lang-text"><span class="typ">End</span><span class="pln"> of assembler </span><span class="kwd">dump</span><span class="pun">.</span></code></li></ol></pre>
      关闭 CANARY 时：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">gdb</span><span class="pun">-</span><span class="pln">peda$ disassemble main</span></code></li><li class="L1"><code class="lang-text"><span class="typ">Dump</span><span class="pln"> of assembler code </span><span class="kwd">for</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> main</span><span class="pun">:</span></code></li><li class="L2"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000055d</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">0</span><span class="pun">&gt;:</span><span class="pln">    lea    ecx</span><span class="pun">,[</span><span class="pln">esp</span><span class="pun">+</span><span class="lit">0x4</span><span class="pun">]</span></code></li><li class="L3"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000561</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">4</span><span class="pun">&gt;:</span><span class="pln">    </span><span class="kwd">and</span><span class="pln">    esp</span><span class="pun">,</span><span class="lit">0xfffffff0</span></code></li><li class="L4"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000564</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">7</span><span class="pun">&gt;:</span><span class="pln">    push   DWORD PTR </span><span class="pun">[</span><span class="pln">ecx</span><span class="pun">-</span><span class="lit">0x4</span><span class="pun">]</span></code></li><li class="L5"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000567</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">10</span><span class="pun">&gt;:</span><span class="pln">    push   ebp</span></code></li><li class="L6"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000568</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">11</span><span class="pun">&gt;:</span><span class="pln">    mov    ebp</span><span class="pun">,</span><span class="pln">esp</span></code></li><li class="L7"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000056a</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">13</span><span class="pun">&gt;:</span><span class="pln">    push   ebx</span></code></li><li class="L8"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000056b</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">14</span><span class="pun">&gt;:</span><span class="pln">    push   ecx</span></code></li><li class="L9"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000056c</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">15</span><span class="pun">&gt;:</span><span class="pln">    </span><span class="kwd">sub</span><span class="pln">    esp</span><span class="pun">,</span><span class="lit">0x10</span></code></li><li class="L0"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000056f</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">18</span><span class="pun">&gt;:</span><span class="pln">    call   </span><span class="lit">0x59c</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">__x86</span><span class="pun">.</span><span class="pln">get_pc_thunk</span><span class="pun">.</span><span class="pln">ax</span><span class="pun">&gt;</span></code></li><li class="L1"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000574</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">23</span><span class="pun">&gt;:</span><span class="pln">    add    eax</span><span class="pun">,</span><span class="lit">0x1a8c</span></code></li><li class="L2"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000579</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">28</span><span class="pun">&gt;:</span><span class="pln">    </span><span class="kwd">sub</span><span class="pln">    esp</span><span class="pun">,</span><span class="lit">0x8</span></code></li><li class="L3"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000057c</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">31</span><span class="pun">&gt;:</span><span class="pln">    lea    edx</span><span class="pun">,[</span><span class="pln">ebp</span><span class="pun">-</span><span class="lit">0x12</span><span class="pun">]</span></code></li><li class="L4"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000057f</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">34</span><span class="pun">&gt;:</span><span class="pln">    push   edx</span></code></li><li class="L5"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000580</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">35</span><span class="pun">&gt;:</span><span class="pln">    lea    edx</span><span class="pun">,[</span><span class="pln">eax</span><span class="pun">-</span><span class="lit">0x19e0</span><span class="pun">]</span></code></li><li class="L6"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000586</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">41</span><span class="pun">&gt;:</span><span class="pln">    push   edx</span></code></li><li class="L7"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000587</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">42</span><span class="pun">&gt;:</span><span class="pln">    mov    ebx</span><span class="pun">,</span><span class="pln">eax</span></code></li><li class="L8"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000589</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">44</span><span class="pun">&gt;:</span><span class="pln">    call   </span><span class="lit">0x400</span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln">__isoc99_scanf@plt</span><span class="pun">&gt;</span></code></li><li class="L9"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000058e</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">49</span><span class="pun">&gt;:</span><span class="pln">    add    esp</span><span class="pun">,</span><span class="lit">0x10</span></code></li><li class="L0"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000591</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">52</span><span class="pun">&gt;:</span><span class="pln">    nop</span></code></li><li class="L1"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000592</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">53</span><span class="pun">&gt;:</span><span class="pln">    lea    esp</span><span class="pun">,[</span><span class="pln">ebp</span><span class="pun">-</span><span class="lit">0x8</span><span class="pun">]</span></code></li><li class="L2"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000595</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">56</span><span class="pun">&gt;:</span><span class="pln">    pop    ecx</span></code></li><li class="L3"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000596</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">57</span><span class="pun">&gt;:</span><span class="pln">    pop    ebx</span></code></li><li class="L4"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000597</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">58</span><span class="pun">&gt;:</span><span class="pln">    pop    ebp</span></code></li><li class="L5"><code class="lang-text"><span class="pln">   </span><span class="lit">0x00000598</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">59</span><span class="pun">&gt;:</span><span class="pln">    lea    esp</span><span class="pun">,[</span><span class="pln">ecx</span><span class="pun">-</span><span class="lit">0x4</span><span class="pun">]</span></code></li><li class="L6"><code class="lang-text"><span class="pln">   </span><span class="lit">0x0000059b</span><span class="pln"> </span><span class="pun">&lt;+</span><span class="lit">62</span><span class="pun">&gt;:</span><span class="pln">    ret</span></code></li><li class="L7"><code class="lang-text"><span class="typ">End</span><span class="pln"> of assembler </span><span class="kwd">dump</span><span class="pun">.</span></code></li></ol></pre>
      <b>FORTIFY</b><br>
      FORTIFY 的选项 -D_FORTIFY_SOURCE 往往和优化 -O 选项一起使用，以检测缓冲区溢出的问题。
      <br>下面是一个简单的例子：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-c"><span class="com">#include</span><span class="str">&lt;string.h&gt;</span></code></li><li class="L1"><code class="lang-c"><span class="kwd">void</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></code></li><li class="L2"><code class="lang-c"><span class="pln">    </span><span class="kwd">char</span><span class="pln"> str</span><span class="pun">[</span><span class="lit">3</span><span class="pun">];</span></code></li><li class="L3"><code class="lang-c"><span class="pln">    strcpy</span><span class="pun">(</span><span class="pln">str</span><span class="pun">,</span><span class="pln"> </span><span class="str">"abcde"</span><span class="pun">);</span></code></li><li class="L4"><code class="lang-c"><span class="pun">}</span></code></li></ol></pre>
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">$ gcc </span><span class="pun">-</span><span class="pln">O2 fortify</span><span class="pun">.</span><span class="pln">c</span></code></li><li class="L1"><code class="lang-text"><span class="pln">$ checksec </span><span class="pun">--</span><span class="pln">file a</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L2"><code class="lang-text"><span class="pln">RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH  FORTIFY </span><span class="typ">Fortified</span><span class="pln"> </span><span class="typ">Fortifiable</span><span class="pln">  FILE</span></code></li><li class="L3"><code class="lang-text"><span class="typ">Partial</span><span class="pln"> RELRO   </span><span class="typ">No</span><span class="pln"> canary found   NX enabled    PIE enabled     </span><span class="typ">No</span><span class="pln"> RPATH   </span><span class="typ">No</span><span class="pln"> RUNPATH   </span><span class="typ">No</span><span class="pln">  </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> a</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L4"><code class="lang-text"></code></li><li class="L5"><code class="lang-text"><span class="pln">$ gcc </span><span class="pun">-</span><span class="pln">O2 </span><span class="pun">-</span><span class="pln">D_FORTIFY_SOURCE</span><span class="pun">=</span><span class="lit">2</span><span class="pln"> fortify</span><span class="pun">.</span><span class="pln">c</span></code></li><li class="L6"><code class="lang-text"><span class="typ">In</span><span class="pln"> file included </span><span class="kwd">from</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">include</span><span class="pun">/</span><span class="kwd">string</span><span class="pun">.</span><span class="pln">h</span><span class="pun">:</span><span class="lit">639</span><span class="pun">:</span><span class="lit">0</span><span class="pun">,</span></code></li><li class="L7"><code class="lang-text"><span class="pln">                 </span><span class="kwd">from</span><span class="pln"> fortify</span><span class="pun">.</span><span class="pln">c</span><span class="pun">:</span><span class="lit">1</span><span class="pun">:</span></code></li><li class="L8"><code class="lang-text"><span class="typ">In</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">strcpy</span><span class="pun">’,</span></code></li><li class="L9"><code class="lang-text"><span class="pln">    inlined </span><span class="kwd">from</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">main</span><span class="pun">’</span><span class="pln"> at fortify</span><span class="pun">.</span><span class="pln">c</span><span class="pun">:</span><span class="lit">4</span><span class="pun">:</span><span class="lit">2</span><span class="pun">:</span></code></li><li class="L0"><code class="lang-text"><span class="str">/usr/</span><span class="pln">include</span><span class="pun">/</span><span class="pln">bits</span><span class="pun">/</span><span class="pln">string3</span><span class="pun">.</span><span class="pln">h</span><span class="pun">:</span><span class="lit">109</span><span class="pun">:</span><span class="lit">10</span><span class="pun">:</span><span class="pln"> warning</span><span class="pun">:</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">__builtin___memcpy_chk</span><span class="pun">’</span><span class="pln"> writing </span><span class="lit">6</span><span class="pln"> bytes </span><span class="kwd">into</span><span class="pln"> a region of size </span><span class="lit">3</span><span class="pln"> overflows the destination </span><span class="pun">[-</span><span class="typ">Wstringop</span><span class="pun">-</span><span class="pln">overflow</span><span class="pun">=]</span></code></li><li class="L1"><code class="lang-text"><span class="pln">   </span><span class="kwd">return</span><span class="pln"> __builtin___strcpy_chk </span><span class="pun">(</span><span class="pln">__dest</span><span class="pun">,</span><span class="pln"> __src</span><span class="pun">,</span><span class="pln"> __bos </span><span class="pun">(</span><span class="pln">__dest</span><span class="pun">));</span></code></li><li class="L2"><code class="lang-text"><span class="pln">          </span><span class="pun">^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</span></code></li><li class="L3"><code class="lang-text"><span class="pln">$ checksec </span><span class="pun">--</span><span class="pln">file a</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L4"><code class="lang-text"><span class="pln">RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH  FORTIFY </span><span class="typ">Fortified</span><span class="pln"> </span><span class="typ">Fortifiable</span><span class="pln">  FILE</span></code></li><li class="L5"><code class="lang-text"><span class="typ">Partial</span><span class="pln"> RELRO   </span><span class="typ">Canary</span><span class="pln"> found      NX enabled    PIE enabled     </span><span class="typ">No</span><span class="pln"> RPATH   </span><span class="typ">No</span><span class="pln"> RUNPATH   </span><span class="typ">Yes</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> a</span><span class="pun">.</span><span class="kwd">out</span></code></li></ol></pre>
      开启优化 -O2 后，编译没有检测出任何问题，checksec 后 FORTIFY 为 No。当配合 -D_FORTIFY_SOURCE=2（也可以 =1）使用时，提示存在溢出问题，checksec 后 FORTIFY 为 Yes。
      <b>NX</b>
      <br>No-eXecute，表示不可执行，其原理是将数据所在的内存页标识为不可执行，如果程序产生溢出转入执行 shellcode 时，CPU 会抛出异常。
      <br>在 Linux 中，当装载器将程序装载进内存空间后，将程序的 .text 段标记为可执行，而其余的数据段（.data、.bss 等）以及栈、堆均为不可执行。因此，传统利用方式中通过修改 GOT 来执行 shellcode 的方式不再可行。
      <br>但这种保护并不能阻止攻击者通过代码重用来进行攻击（ret2libc）。
      <b>PIE</b>
      <br>PIE（Position Independent Executable）需要配合 ASLR 来使用，以达到可执行文件的加载时地址随机化。简单来说，PIE 是编译时随
      <br>机化，由编译器完成；ASLR 是加载时随机化，由操作系统完成。ASLR 将程序运行时的堆栈以及共享库的加载地址随机化，而 PIE 在编译
      <br>时将程序编译为位置无关、即程序运行时各个段加载的虚拟地址在装载时确定。开启 PIE 时，编译生成的是动态库文件（Shared object）
      <br>文件，而关闭 PIE 后生成可执行文件（Executable）。
      <br>我们通过实际例子来探索一下 PIE 和 ASLR：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-c"><span class="com">#include</span><span class="str">&lt;stdio.h&gt;</span></code></li><li class="L1"><code class="lang-c"><span class="kwd">void</span><span class="pln"> main</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span></code></li><li class="L2"><code class="lang-c"><span class="pln">    printf</span><span class="pun">(</span><span class="str">"%p\n"</span><span class="pun">,</span><span class="pln"> main</span><span class="pun">);</span></code></li><li class="L3"><code class="lang-c"><span class="pun">}</span></code></li></ol></pre>
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">$ gcc </span><span class="pun">-</span><span class="pln">m32 </span><span class="pun">-</span><span class="pln">pie random</span><span class="pun">.</span><span class="pln">c </span><span class="pun">-</span><span class="pln">o open</span><span class="pun">-</span><span class="pln">pie</span></code></li><li class="L1"><code class="lang-text"><span class="pln">$ readelf </span><span class="pun">-</span><span class="pln">h open</span><span class="pun">-</span><span class="pln">pie</span></code></li><li class="L2"><code class="lang-text"><span class="pln">ELF </span><span class="typ">Header</span><span class="pun">:</span></code></li><li class="L3"><code class="lang-text"><span class="pln">  </span><span class="typ">Magic</span><span class="pun">:</span><span class="pln">   </span><span class="lit">7f</span><span class="pln"> </span><span class="lit">45</span><span class="pln"> </span><span class="lit">4c</span><span class="pln"> </span><span class="lit">46</span><span class="pln"> </span><span class="lit">01</span><span class="pln"> </span><span class="lit">01</span><span class="pln"> </span><span class="lit">01</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span><span class="pln"> </span><span class="lit">00</span></code></li><li class="L4"><code class="lang-text"><span class="pln">  </span><span class="typ">Class</span><span class="pun">:</span><span class="pln">                             ELF32</span></code></li><li class="L5"><code class="lang-text"><span class="pln">  </span><span class="typ">Data</span><span class="pun">:</span><span class="pln">                              </span><span class="lit">2</span><span class="str">'s complement, little endian</span></code></li><li class="L6"><code class="lang-text"><span class="str">  Version:                           1 (current)</span></code></li><li class="L7"><code class="lang-text"><span class="str">  OS/ABI:                            UNIX - System V</span></code></li><li class="L8"><code class="lang-text"><span class="str">  ABI Version:                       0</span></code></li><li class="L9"><code class="lang-text"><span class="str">  Type:                              DYN (Shared object file)</span></code></li><li class="L0"><code class="lang-text"><span class="str">  Machine:                           Intel 80386</span></code></li><li class="L1"><code class="lang-text"><span class="str">  Version:                           0x1</span></code></li><li class="L2"><code class="lang-text"><span class="str">  Entry point address:               0x400</span></code></li><li class="L3"><code class="lang-text"><span class="str">  Start of program headers:          52 (bytes into file)</span></code></li><li class="L4"><code class="lang-text"><span class="str">  Start of section headers:          6132 (bytes into file)</span></code></li><li class="L5"><code class="lang-text"><span class="str">  Flags:                             0x0</span></code></li><li class="L6"><code class="lang-text"><span class="str">  Size of this header:               52 (bytes)</span></code></li><li class="L7"><code class="lang-text"><span class="str">  Size of program headers:           32 (bytes)</span></code></li><li class="L8"><code class="lang-text"><span class="str">  Number of program headers:         9</span></code></li><li class="L9"><code class="lang-text"><span class="str">  Size of section headers:           40 (bytes)</span></code></li><li class="L0"><code class="lang-text"><span class="str">  Number of section headers:         30</span></code></li><li class="L1"><code class="lang-text"><span class="str">  Section header string table index: 29</span></code></li><li class="L2"><code class="lang-text"><span class="str">$ gcc -m32 -no-pie random.c -o close-pie</span></code></li><li class="L3"><code class="lang-text"><span class="str">$ readelf -h close-pie</span></code></li><li class="L4"><code class="lang-text"><span class="str">ELF Header:</span></code></li><li class="L5"><code class="lang-text"><span class="str">  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00</span></code></li><li class="L6"><code class="lang-text"><span class="str">  Class:                             ELF32</span></code></li><li class="L7"><code class="lang-text"><span class="str">  Data:                              2'</span><span class="pln">s complement</span><span class="pun">,</span><span class="pln"> little endian</span></code></li><li class="L8"><code class="lang-text"><span class="pln">  </span><span class="typ">Version</span><span class="pun">:</span><span class="pln">                           </span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="pln">current</span><span class="pun">)</span></code></li><li class="L9"><code class="lang-text"><span class="pln">  OS</span><span class="pun">/</span><span class="pln">ABI</span><span class="pun">:</span><span class="pln">                            UNIX </span><span class="pun">-</span><span class="pln"> </span><span class="typ">System</span><span class="pln"> V</span></code></li><li class="L0"><code class="lang-text"><span class="pln">  ABI </span><span class="typ">Version</span><span class="pun">:</span><span class="pln">                       </span><span class="lit">0</span></code></li><li class="L1"><code class="lang-text"><span class="pln">  </span><span class="typ">Type</span><span class="pun">:</span><span class="pln">                              EXEC </span><span class="pun">(</span><span class="typ">Executable</span><span class="pln"> file</span><span class="pun">)</span></code></li><li class="L2"><code class="lang-text"><span class="pln">  </span><span class="typ">Machine</span><span class="pun">:</span><span class="pln">                           </span><span class="typ">Intel</span><span class="pln"> </span><span class="lit">80386</span></code></li><li class="L3"><code class="lang-text"><span class="pln">  </span><span class="typ">Version</span><span class="pun">:</span><span class="pln">                           </span><span class="lit">0x1</span></code></li><li class="L4"><code class="lang-text"><span class="pln">  </span><span class="typ">Entry</span><span class="pln"> point address</span><span class="pun">:</span><span class="pln">               </span><span class="lit">0x8048310</span></code></li><li class="L5"><code class="lang-text"><span class="pln">  </span><span class="typ">Start</span><span class="pln"> of program headers</span><span class="pun">:</span><span class="pln">          </span><span class="lit">52</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bytes </span><span class="kwd">into</span><span class="pln"> file</span><span class="pun">)</span></code></li><li class="L6"><code class="lang-text"><span class="pln">  </span><span class="typ">Start</span><span class="pln"> of section headers</span><span class="pun">:</span><span class="pln">          </span><span class="lit">5964</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bytes </span><span class="kwd">into</span><span class="pln"> file</span><span class="pun">)</span></code></li><li class="L7"><code class="lang-text"><span class="pln">  </span><span class="typ">Flags</span><span class="pun">:</span><span class="pln">                             </span><span class="lit">0x0</span></code></li><li class="L8"><code class="lang-text"><span class="pln">  </span><span class="typ">Size</span><span class="pln"> of </span><span class="kwd">this</span><span class="pln"> header</span><span class="pun">:</span><span class="pln">               </span><span class="lit">52</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bytes</span><span class="pun">)</span></code></li><li class="L9"><code class="lang-text"><span class="pln">  </span><span class="typ">Size</span><span class="pln"> of program headers</span><span class="pun">:</span><span class="pln">           </span><span class="lit">32</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bytes</span><span class="pun">)</span></code></li><li class="L0"><code class="lang-text"><span class="pln">  </span><span class="typ">Number</span><span class="pln"> of program headers</span><span class="pun">:</span><span class="pln">         </span><span class="lit">9</span></code></li><li class="L1"><code class="lang-text"><span class="pln">  </span><span class="typ">Size</span><span class="pln"> of section headers</span><span class="pun">:</span><span class="pln">           </span><span class="lit">40</span><span class="pln"> </span><span class="pun">(</span><span class="pln">bytes</span><span class="pun">)</span></code></li><li class="L2"><code class="lang-text"><span class="pln">  </span><span class="typ">Number</span><span class="pln"> of section headers</span><span class="pun">:</span><span class="pln">         </span><span class="lit">30</span></code></li><li class="L3"><code class="lang-text"><span class="pln">  </span><span class="typ">Section</span><span class="pln"> header </span><span class="kwd">string</span><span class="pln"> table index</span><span class="pun">:</span><span class="pln"> </span><span class="lit">29</span></code></li></ol></pre>
      可以看到两者的不同在 Type 和 Entry point address。
      <br>首先我们关闭 ASLR，使用 -pie 进行编译：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="com"># echo 0 &gt; /proc/sys/kernel/randomize_va_space</span></code></li><li class="L1"><code class="lang-text"><span class="com"># gcc -m32 -pie random.c -o a.out</span></code></li><li class="L2"><code class="lang-text"><span class="com"># checksec --file a.out</span></code></li><li class="L3"><code class="lang-text"><span class="pln">RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH    FORTIFY    </span><span class="typ">Fortified</span><span class="pln"> </span><span class="typ">Fortifiable</span><span class="pln">  FILE</span></code></li><li class="L4"><code class="lang-text"><span class="typ">Partial</span><span class="pln"> RELRO   </span><span class="typ">No</span><span class="pln"> canary found   NX enabled    PIE enabled     </span><span class="typ">No</span><span class="pln"> RPATH   </span><span class="typ">No</span><span class="pln"> RUNPATH   </span><span class="typ">No</span><span class="pln">    </span><span class="lit">0</span><span class="pln">        </span><span class="lit">2</span><span class="pln">    a</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L5"><code class="lang-text"></code></li><li class="L6"><code class="lang-text"><span class="com"># ./a.out</span></code></li><li class="L7"><code class="lang-text"><span class="lit">0x5655553d</span></code></li><li class="L8"><code class="lang-text"><span class="com"># ./a.out</span></code></li><li class="L9"><code class="lang-text"><span class="lit">0x5655553d</span></code></li></ol></pre>
      <br>我们虽然开启了 -pie，但是 ASLR 被关闭，入口地址不变。
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="com"># ldd a.out</span></code></li><li class="L1"><code class="lang-text"><span class="pln">  linux</span><span class="pun">-</span><span class="pln">gate</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7fd7000</span><span class="pun">)</span></code></li><li class="L2"><code class="lang-text"><span class="pln">  libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib32</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7dd9000</span><span class="pun">)</span></code></li><li class="L3"><code class="lang-text"><span class="pln">  </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7fd9000</span><span class="pun">)</span></code></li><li class="L4"><code class="lang-text"><span class="com"># ldd a.out</span></code></li><li class="L5"><code class="lang-text"><span class="pln">  linux</span><span class="pun">-</span><span class="pln">gate</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7fd7000</span><span class="pun">)</span></code></li><li class="L6"><code class="lang-text"><span class="pln">  libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib32</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7dd9000</span><span class="pun">)</span></code></li><li class="L7"><code class="lang-text"><span class="pln">  </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7fd9000</span><span class="pun">)</span></code></li></ol></pre>
      可以看出动态链接库地址也不变。然后我们开启 ASLR：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="com"># echo 2 &gt; /proc/sys/kernel/randomize_va_space</span></code></li><li class="L1"><code class="lang-text"><span class="com"># ./a.out</span></code></li><li class="L2"><code class="lang-text"><span class="lit">0x5665353d</span></code></li><li class="L3"><code class="lang-text"><span class="com"># ./a.out</span></code></li><li class="L4"><code class="lang-text"><span class="lit">0x5659753d</span></code></li><li class="L5"><code class="lang-text"><span class="com"># ldd a.out</span></code></li><li class="L6"><code class="lang-text"><span class="pln">  linux</span><span class="pun">-</span><span class="pln">gate</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7727000</span><span class="pun">)</span></code></li><li class="L7"><code class="lang-text"><span class="pln">  libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib32</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7529000</span><span class="pun">)</span></code></li><li class="L8"><code class="lang-text"><span class="pln">  </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7729000</span><span class="pun">)</span></code></li><li class="L9"><code class="lang-text"><span class="com"># ldd a.out</span></code></li><li class="L0"><code class="lang-text"><span class="pln">  linux</span><span class="pun">-</span><span class="pln">gate</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf77d6000</span><span class="pun">)</span></code></li><li class="L1"><code class="lang-text"><span class="pln">  libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib32</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf75d8000</span><span class="pun">)</span></code></li><li class="L2"><code class="lang-text"><span class="pln">  </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf77d8000</span><span class="pun">)</span></code></li></ol></pre>
      入口地址和动态链接库地址都变得随机。
      <br>接下来关闭 ASLR，并使用 -no-pie 进行编译：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="com"># echo 0 &gt; /proc/sys/kernel/randomize_va_space</span></code></li><li class="L1"><code class="lang-text"><span class="com"># gcc -m32 -no-pie random.c -o b.out</span></code></li><li class="L2"><code class="lang-text"><span class="com"># checksec --file b.out</span></code></li><li class="L3"><code class="lang-text"><span class="pln">RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH  FORTIFY </span><span class="typ">Fortified</span><span class="pln"> </span><span class="typ">Fortifiable</span><span class="pln">  FILE</span></code></li><li class="L4"><code class="lang-text"><span class="typ">Partial</span><span class="pln"> RELRO   </span><span class="typ">No</span><span class="pln"> canary found   NX enabled    </span><span class="typ">No</span><span class="pln"> PIE          </span><span class="typ">No</span><span class="pln"> RPATH   </span><span class="typ">No</span><span class="pln"> RUNPATH   </span><span class="typ">No</span><span class="pln">  </span><span class="lit">0</span><span class="pln">   </span><span class="lit">2</span><span class="pln"> b</span><span class="pun">.</span><span class="kwd">out</span></code></li><li class="L5"><code class="lang-text"></code></li><li class="L6"><code class="lang-text"><span class="com"># ./b.out</span></code></li><li class="L7"><code class="lang-text"><span class="lit">0x8048406</span></code></li><li class="L8"><code class="lang-text"><span class="com"># ./b.out</span></code></li><li class="L9"><code class="lang-text"><span class="lit">0x8048406</span></code></li><li class="L0"><code class="lang-text"><span class="com"># ldd b.out</span></code></li><li class="L1"><code class="lang-text"><span class="pln">  linux</span><span class="pun">-</span><span class="pln">gate</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7fd7000</span><span class="pun">)</span></code></li><li class="L2"><code class="lang-text"><span class="pln">  libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib32</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7dd9000</span><span class="pun">)</span></code></li><li class="L3"><code class="lang-text"><span class="pln">  </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7fd9000</span><span class="pun">)</span></code></li><li class="L4"><code class="lang-text"><span class="com"># ldd b.out</span></code></li><li class="L5"><code class="lang-text"><span class="pln">  linux</span><span class="pun">-</span><span class="pln">gate</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7fd7000</span><span class="pun">)</span></code></li><li class="L6"><code class="lang-text"><span class="pln">  libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib32</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7dd9000</span><span class="pun">)</span></code></li><li class="L7"><code class="lang-text"><span class="pln">  </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7fd9000</span><span class="pun">)</span></code></li></ol></pre>
      入口地址和动态库都是固定的。下面开启 ASLR：
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="com"># echo 2 &gt; /proc/sys/kernel/randomize_va_space</span></code></li><li class="L1"><code class="lang-text"><span class="com"># ./b.out</span></code></li><li class="L2"><code class="lang-text"><span class="lit">0x8048406</span></code></li><li class="L3"><code class="lang-text"><span class="com"># ./b.out</span></code></li><li class="L4"><code class="lang-text"><span class="lit">0x8048406</span></code></li><li class="L5"><code class="lang-text"><span class="com"># ldd b.out</span></code></li><li class="L6"><code class="lang-text"><span class="pln">  linux</span><span class="pun">-</span><span class="pln">gate</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7797000</span><span class="pun">)</span></code></li><li class="L7"><code class="lang-text"><span class="pln">  libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib32</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7599000</span><span class="pun">)</span></code></li><li class="L8"><code class="lang-text"><span class="pln">  </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf7799000</span><span class="pun">)</span></code></li><li class="L9"><code class="lang-text"><span class="com"># ldd b.out</span></code></li><li class="L0"><code class="lang-text"><span class="pln">  linux</span><span class="pun">-</span><span class="pln">gate</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">1</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf770a000</span><span class="pun">)</span></code></li><li class="L1"><code class="lang-text"><span class="pln">  libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">=&gt;</span><span class="pln"> </span><span class="pun">/</span><span class="pln">usr</span><span class="pun">/</span><span class="pln">lib32</span><span class="pun">/</span><span class="pln">libc</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">6</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf750c000</span><span class="pun">)</span></code></li><li class="L2"><code class="lang-text"><span class="pln">  </span><span class="pun">/</span><span class="pln">lib</span><span class="pun">/</span><span class="pln">ld</span><span class="pun">-</span><span class="pln">linux</span><span class="pun">.</span><span class="pln">so</span><span class="pun">.</span><span class="lit">2</span><span class="pln"> </span><span class="pun">(</span><span class="lit">0xf770c000</span><span class="pun">)</span></code></li></ol></pre>
      入口地址依然固定，但是动态库变为随机。
      所以在分析一个 PIE 开启的二进制文件时，只需要关闭 ASLR，即可使 PIE 和 ASLR 都失效。
      <br>ASLR（Address Space Layout Randomization）
      <br>关闭：# echo 0 > /proc/sys/kernel/randomize_va_space
      <br>部分开启（将 mmap 的基址，stack 和 vdso 页面随机化）：# echo 1 > /proc/sys/kernel/randomize_va_space
      <br>完全开启（在部分开启的基础上增加 heap的随机化：# echo ２ > /proc/sys/kernel/randomize_va_space
      <b>RELRO</b>
      RELRO（ReLocation Read-Only）设置符号重定向表为只读或在程序启动时就解析并绑定所有动态符号，从而减少对 GOT（Global Offset Table）的攻击。
      <br>RELOR 有两种形式：
      <ul>
        <li style="margin-left: 2em;">Partial RELRO：一些段（包括 .dynamic）在初始化后将会被标记为只读。</li>
        <li style="margin-left: 2em;">Full RELRO：除了 Partial RELRO，延迟绑定将被禁止，所有的导入符号将在开始时被解析，.got.plt 段会被完全初始化为目标函数的最终地址，并被标记为只读。另外 link_map 和 _dl_runtime_resolve 的地址也不会被装入。</li>
      </ul>

      <h3>编译参数</h3>
      各种安全技术的编译参数如下：
      <table>
        <thead>
        <tr>
          <th>安全技术</th>
          <th>完全开启</th>
          <th>部分开启</th>
          <th>关闭</th>
        </tr>
        </thead>
        <tbody>
        <tr>
          <td>Canary</td>
          <td>-fstack-protector-all</td>
          <td>-fstack-protector</td>
          <td>-fno-stack-protector</td>
        </tr>
        <tr>
          <td>NX</td>
          <td>-z noexecstack</td>
          <td></td>
          <td>-z execstack</td>
        </tr>
        <tr>
          <td>PIE</td>
          <td>-pie</td>
          <td></td>
          <td>-no-pie</td>
        </tr>
        <tr>
          <td>RELRO</td>
          <td>-z now</td>
          <td>-z lazy</td>
          <td>-z norelro</td>
        </tr>
        </tbody>
      </table>
      关闭所有保护：
      <br>gcc hello.c -o hello -fno-stack-protector -z execstack -no-pie -z norelro
      <br>开启所有保护：
      <br>gcc hello.c -o hello -fstack-protector-all -z noexecstack -pie -z now
      <ul>
        <li style="margin-left: 2em;">-D_FORTIFY_SOURCE=1：仅在编译时检测溢出</li>
        <li style="margin-left: 2em;">-D_FORTIFY_SOURCE=2：在编译时和运行时检测溢出</li>
      </ul>
      <h3>保护机制检测</h3>
      有许多工具可以检测二进制文件所使用的编译器安全技术。下面介绍常用的几种：
      <br><b>checksec</b>
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">$ checksec </span><span class="pun">--</span><span class="pln">file </span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">ls</span></code></li><li class="L1"><code class="lang-text"><span class="pln">RELRO           STACK CANARY      NX            PIE             RPATH      RUNPATH    FORTIFY    </span><span class="typ">Fortified</span><span class="pln"> </span><span class="typ">Fortifiable</span><span class="pln">  FILE</span></code></li><li class="L2"><code class="lang-text"><span class="typ">Partial</span><span class="pln"> RELRO   </span><span class="typ">Canary</span><span class="pln"> found      NX enabled    </span><span class="typ">No</span><span class="pln"> PIE          </span><span class="typ">No</span><span class="pln"> RPATH   </span><span class="typ">No</span><span class="pln"> RUNPATH   </span><span class="typ">Yes</span><span class="pln">    </span><span class="lit">5</span><span class="pln">        </span><span class="lit">15</span><span class="pln">    </span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">ls</span></code></li></ol></pre>
      peda 自带的 checksec
      <pre style="margin-left: 2em;"><ol class="linenums"><li class="L0"><code class="lang-text"><span class="pln">$ gdb </span><span class="pun">/</span><span class="pln">bin</span><span class="pun">/</span><span class="pln">ls</span></code></li><li class="L1"><code class="lang-text"><span class="pln">gdb</span><span class="pun">-</span><span class="pln">peda$ checksec</span></code></li><li class="L2"><code class="lang-text"><span class="pln">CANARY    </span><span class="pun">:</span><span class="pln"> ENABLED</span></code></li><li class="L3"><code class="lang-text"><span class="pln">FORTIFY   </span><span class="pun">:</span><span class="pln"> ENABLED</span></code></li><li class="L4"><code class="lang-text"><span class="pln">NX        </span><span class="pun">:</span><span class="pln"> ENABLED</span></code></li><li class="L5"><code class="lang-text"><span class="pln">PIE       </span><span class="pun">:</span><span class="pln"> disabled</span></code></li><li class="L6"><code class="lang-text"><span class="pln">RELRO     </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Partial</span></code></li></ol></pre>
      <h3>地址空间布局随机化</h3>
      最后再说一下地址空间布局随机化（ASLR），该技术虽然不是由 GCC 编译时提供的，但对 PIE 还是有影响。该技术旨在将程序的内存布
      <br>局随机化，使得攻击者不能轻易地得到数据区的地址来构造 payload。由于程序的堆栈分配与共享库的装载都是在运行时进行，系统在程
      <br>序每次执行时，随机地分配程序堆栈的地址以及共享库装载的地址。使得攻击者无法预测自己写入的数据区的虚拟地址。
      <br>针对该保护机制的攻击，往往是通过信息泄漏来实现。由于同一模块中的所有代码和数据的相对偏移是固定的，攻击者只要泄漏出某个模
      <br>块中的任一代码指针或数据指针，即可通过计算得到此模块中任意代码或数据的地址。

      <el-divider></el-divider>

      <h3>GCC 中用于启用堆栈保护技术的编译选项是什么？</h3>
      <el-radio-group v-model="radio">
        <el-radio :label="1">-fno-stack-protector</el-radio>
        <el-radio :label="2">-fstack-protector</el-radio>
        <el-radio :label="3">-fstack-protector-all</el-radio>
        <el-radio :label="4">-fstack-protector-strong</el-radio>
        <el-button type="primary" plain :disabled="isButtonDisabled" @click="check(radio)">检查</el-button>
      </el-radio-group>
    </div>
    <el-divider></el-divider>

  </div>
</template>

<style scoped>
table {
  border-collapse: collapse;
  width: 100%;
}

th, td {
  border: 1px solid black;
  padding: 8px;
  text-align: left;
}
</style>